import React from 'react';
import { Table } from 'antd'
import { Resizable } from 'react-resizable';
import { DragSource, DropTarget } from 'react-dnd';
import withDragDropContext from 'components/with-dnd-context';
import 'styles/components/resize-table/resize-table.scss'
import ReactDOM from "react-dom";
import ResizeTableUtils from './resize-table-utils'

/**
 * 可调节的列，用react-resize包裹，Table内components使用
 */
let draggingIndex = -1;

class ResizeableTitle extends React.Component {
  render() {
    const {
      isOver, index, resizing, onMove,
      connectDragSource, connectDropTarget,
      onResize, onResizeStart, onResizeStop, width,
      ...restProps
    } = this.props;
    const style = { ...restProps.style, cursor: 'move' };
    let { className } = restProps;
    if (isOver) {
      if (index > draggingIndex) {
        className += ' drop-over-backward';
      }
      if (index < draggingIndex) {
        className += ' drop-over-frontward';
      }
    }
    //没有宽度无法计算
    if (!width) {
      return <th {...restProps} />;
    }
    return (
      <Resizable
        width={width}
        height={0}
        onResize={onResize}
        onResizeStart={onResizeStart}
        onResizeStop={onResizeStop}
      >
        {connectDragSource(
            connectDropTarget(<th {...restProps} style={style} className={className}/>)
          )}
      </Resizable>);

  }
}

const rowSource = {

  beginDrag(props) {
    draggingIndex = props.index;
    return {
      index: props.index,
    };
  },

  canDrag(props) {
    return !props.resizing
  }
};

const rowTarget = {
  drop(props, monitor) {
    const dragIndex = monitor.getItem().index;
    const hoverIndex = props.index;
    if (dragIndex === hoverIndex) {
      return;
    }
    props.onMove(dragIndex, hoverIndex);
    monitor.getItem().index = hoverIndex;
  }
};

const DraggableHeaderCell = DropTarget('th', rowTarget, (connect, monitor) => ({
  connectDropTarget: connect.dropTarget(),
  isOver: monitor.isOver()
}))(
  DragSource('th', rowSource, connect => ({
    connectDragSource: connect.dragSource(),
  }))(ResizeableTitle),
);

/**
 * 可拖拽调节列宽度的表格
 * @param props
 * @return {*}
 * @constructor
 */
class ResizeTable extends React.Component {

  constructor(props){
    super(props);
    this.state = {
      columns: [],
      resizing: false,
      loading: true,
      gettingColumns: false
    };
    this.minSize = props.minSize;
  }

  copyColumns = columns => columns.map(c => ({ ...c }));

  componentDidMount() {
    const { columns, onRef } = this.props;
    onRef && onRef(this);
    this.resetColumns(this.copyColumns(columns));
  }

  tableDomWidth = 0;
  extraDomWidth = 0;

  

  resetColumns = (columns, handle) => {
    let filterColumns = columns.filter(c => !c.hide);
    this.setState({ columns: filterColumns }, () => {
      setTimeout(() => {
        if(!this.tableDomWidth) {
          let mainDom = ReactDOM.findDOMNode(this.refs.main);
          this.tableDomWidth = mainDom.parentNode.getBoundingClientRect().width;
          let selection = mainDom.getElementsByClassName('ant-table-selection-column');
          let expand = mainDom.getElementsByClassName('ant-table-expand-icon-th');
          this.extraDomWidth = 0;
          if(selection.length > 0) {
            this.extraDomWidth += selection[0].getBoundingClientRect().width;
          }
          if(expand.length > 0){
            this.extraDomWidth += expand[0].getBoundingClientRect().width;
          }
          this.tableDomWidth -= this.extraDomWidth;
        }
        let nextColumns = this.computeWidth(filterColumns, this.tableDomWidth);
        this.setState({
          columns: nextColumns,
          columnsSum: nextColumns.reduce((total, c) => total + c.width, 0),
          loading: false
        }, () => {
          handle && handle(this.getReturnColumns(nextColumns, columns));
        }, 0);
      });
    });
  };

  componentWillReceiveProps(nextProps) {
    const { resizing, columns } = this.state;
    let needReset = false;
    if(columns.length !== nextProps.columns.length) {
      needReset = true;
    } else {
      columns.map(c => {
        if(!nextProps.columns.find(column => column.dataIndex === c.dataIndex))
          needReset = true;
      })
    }
    !resizing && needReset && this.resetColumns(this.copyColumns(nextProps.columns));
  }

  /**
   * 手动刷新内部表格columns属性
   * 因为willReceiveProps里只判断了顺序、个数和宽度，其他没有判断
   * 其他属性如果需要在外部随时更改则需要手动调用这个函数
   * @param attr 属性更新数组
   * @param callback 回调
   */
  refreshTableColumns = (attr = [], callback = () => {}) => {
    const { columns } = this.state;
    this.setState({
      columns: columns.map(c => {
        let targetAttr = {};
        this.props.columns.map(pc => {
          if(pc.dataIndex === c.dataIndex) {
            attr.map(a => {
              targetAttr[a] = pc[a];
            })
          }
        });
        return { ...c, ...targetAttr };
      })
    }, callback)
  };

  /**`
   * 因为react-resize需要确切知道每一列的宽度，所以这里通过传入的columns计算每一列确切的px
   * @param columns 表格的columns
   * @param tableWidth 表格的整体宽度
   * @return {*}
   */
  computeWidth = (columns, tableWidth) => {
    let totalPx = 0;
    //将百分比和px转换为数字
    columns.forEach(c => {
      if(c.width) {
        if(typeof c.width === 'number') {
          totalPx += c.width;
        } else {
          if(c.width.endsWith('px')) {
            c.width = Number(c.width.substr(0, c.width.length - 2));
            totalPx += c.width;
          } else {
            c.width = Number(c.width.substr(0, c.width.length - 1)) * 0.01 * tableWidth;
            totalPx += c.width
          }
        }
      }
      return c;
    });
    let autoColumnsCount = columns.filter(c => !c.width).length;
    //计算宽度为auto的确切px宽度
    let columnsTotal = 0;
    return columns.map((c, index) => {
      if(!c.width) {
        c.width = Math.floor((tableWidth - totalPx) / autoColumnsCount) - 1;
      }
      if(c.width < this.minSize) {
        c.width = this.minSize;
      }
      columnsTotal += c.width;
      if(index === columns.length - 1 && columnsTotal < tableWidth)
        c.width += (tableWidth - columnsTotal - 1);
      return c;
    })
  };

  handleResize = (e, size, index) => {
    console.log(e,size,index,'targetColumns');
    this.setState(({ columns }) => {
      const nextColumns = [...columns];
      nextColumns[index] = {
        ...nextColumns[index],
        width: size.width < this.minSize ? this.minSize : size.width,
      };
      let ColumnsSum = nextColumns.reduce((total, c) => total + c.width, 0);
      if(ColumnsSum < this.tableDomWidth) {
        let offset = this.tableDomWidth - ColumnsSum;
        nextColumns[columns.length - 1].width += (offset - 1);
      }
      this.setState({ columnsSum: nextColumns.reduce((total, c) => total + c.width, 0) });
      return { columns: nextColumns };
    });
  };

  handleMove = (dragIndex, hoverIndex) => {
    const { columns } = this.state;
    const { onSort } = this.props;
    let columnsTemp = columns.slice();
    let dragFixed = columnsTemp[dragIndex].fixed;
    let hoverFixed = columnsTemp[hoverIndex].fixed;
    if(
      (dragFixed === hoverFixed) ||
      (dragFixed === true && hoverFixed === 'left') ||
      (dragFixed === 'left' && hoverFixed === true)
    )
      columnsTemp.splice(hoverIndex, 1, ...columnsTemp.splice(dragIndex, 1, columnsTemp[hoverIndex]));
    this.setState({ columns: columnsTemp }, () => onSort(this.getReturnColumns(columnsTemp)));
  };

  //表格components自定义表格元素
  components = {
    header: {
      cell: DraggableHeaderCell,
    },
  };

  onChangeColumns = targetColumns => {
    const { onHide } = this.props;
    this.resetColumns(targetColumns, onHide);
  };

  getReturnColumns = (target, allColumns) => {
    const { columns } = this.props;
    let source = allColumns || columns;
    return [...target, ...source.filter(c => !target.find(t => t.dataIndex === c.dataIndex))]
  };

  render() {
    const { columns, columnsSum, resizing, loading, gettingColumns } = this.state;
    const { onResize, showUtils, tableName, hideScroll } = this.props;
    const allColumns = this.props.columns;
    //react-resize方法注入
    const wrappedColumns = columns.map((col, index) => ({
      ...col,
      onHeaderCell: column => ({
        index: index,
        width: column.width,
        resizing,
        onResize: (e, {size}) => this.handleResize(e, size, index),
        onResizeStart: () => this.setState({ resizing: true }),
        onResizeStop: () => this.setState({ resizing: false }, () => onResize(this.getReturnColumns(columns))),
        onMove: this.handleMove
      }),
    }));
    const noSelect = {
      userSelect: "none",
      WebkitUserSelect: "none",
      MsUserSelect: "none",
      MozUserSelect: "none"
    };
    const isSafari = /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);
    const { className, scrollY } = this.props;
    return (
      <div ref="main" style={{ width: '100%' }} className='resize-table-container'>
        {showUtils && <ResizeTableUtils
          columns={allColumns}
          onChange={this.onChangeColumns}
          tableName={tableName}
          onChangeColumnsLoading={gettingColumns => this.setState({ gettingColumns })}
        />}
        <Table
          style={resizing ? noSelect : {}}
          {...Object.assign(
            {},
            this.props,
            {
              className: this.classNames(['resize-table', { [className]: className }]),
              loading: loading || gettingColumns || this.props.loading
            }
          )}
          // scroll={hideScroll ? {} : isSafari ? { x: columnsSum } : { x: columnsSum, y: scrollY }}
          components={this.components}
          columns={wrappedColumns}
          bordered
        />
      </div>
    );
  }

}

ResizeTable.PropTypes = {
  onResize: React.PropTypes.func,
  onSort: React.PropTypes.func,
  onHide: React.PropTypes.func,
  showUtils: React.PropTypes.bool,
  tableName: React.PropTypes.string,
  minSize: React.PropTypes.number
};

ResizeTable.defaultProps = {
  onResize: () => {},
  onSort: () => {},
  onHide: () => {},
  columns: [],
  showUtils: false,
  minSize: 54
};

export default withDragDropContext(ResizeTable)
